package com.cloudinnov.utils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.cloudinnov.utils.support.spring.SpringUtils;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

public class Nksocket extends Thread {
	public String ip = null;// 连接服务器的IP
	public Integer port = null;// 连接服务器的端口
	private Socket socket = null;// 套节字对象
	private boolean close = false; // 关闭连接标志位，true表示关闭，false表示连接
	private Integer sotimeout = 1 * 1 * 5000;// 超时时间，以毫秒为单位
	// ------------------------------------------------------------------------------
	private static final Logger LOG = LoggerFactory.getLogger(LightDetectorClient.class);
	public static final String TOTAL_CAR = "total:light";
	public static final String CAL_NAME = "light:deviceId:";
	public static final String CAL_VALUE = ":value";
	private static final int RECENT_LIST_COUNT = 10000;
	public static final String SPLITTER_LEVEL0 = ",";
	private String equipCode;
	static JedisPool jedisPool = SpringUtils.getBean("jedisPool");
	/**
	 * 测试
	 * 
	 * @param ags
	 */
	public static void main(String[] ags) {
		Nksocket nksocket = new Nksocket("127.0.0.1", 4196,"aaa");
		nksocket.start();
	}

	public Nksocket() {
		init();
	}

	public Nksocket(String ip, Integer port) {
		setIp(ip);
		setPort(port);
		init();
	}
	public Nksocket(String ip,Integer port,String equipCode){
		this.ip=ip;
		this.port=port;
		this.equipCode=equipCode;
		init();
		
	}

	/**
	 * 初始化socket对象
	 */
	public void init() {
		try {
			InetAddress address = InetAddress.getByName(getIp());
			socket = new Socket(address, getPort());
			socket.setKeepAlive(true);// 开启保持活动状态的套接字
			socket.setSoTimeout(sotimeout);// 设置超时时间
			close = !Send(socket, "2");// 发送初始数据，发送成功则表示已经连接上，发送失败表示已经断开
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 读数据线程
	 */
	public void run() {
		Jedis redis = null;
		redis = jedisPool.getResource();
		while (true) {
			// ---------读数据---------------------------
			close = isServerClose(socket);// 判断是否断开
			if (!close) {// 没有断开，开始读数据
				 ReadText(socket,redis);
			}
			// ---------创建连接-------------------------
			while (close) {// 已经断开，重新建立连接
				try {
					 
					LOG.info("能见度检测器："+equipCode+"重新建立连接");
					InetAddress address = InetAddress.getByName(getIp());
					socket = new Socket(address, getPort());
					socket.setKeepAlive(true);
					socket.setSoTimeout(sotimeout);
					close = !Send(socket, "2");
					 
					LOG.info("能见度检测器："+equipCode+"重新建立连接成功");
				} catch (Exception se) {
				 
					LOG.error("能见度检测器："+equipCode+"重新建立连接失败");
					close = true;
				}
			}
		}
	}

	/**
	 * 发送数据，发送失败返回false,发送成功返回true
	 * 
	 * @param csocket
	 * @param message
	 * @return
	 */
	public Boolean Send(Socket csocket, String message) {
		try {
			PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
			out.println(message);
			return true;
		} catch (Exception se) {
			se.printStackTrace();
			return false;
		}
	}

	/**
	 * 读取数据，返回字符串类型
	 * 
	 * @param csocket
	 * @return
	 */
	public void ReadText(Socket csocket,Jedis redis) {
		
		int bytesRcvd;
		byte[] tmp = new byte[1024];
		try {
			csocket.setSoTimeout(sotimeout);
			InputStream input = csocket.getInputStream();
			int totalBytesRcvd = 0;
			if ((bytesRcvd = input.read(tmp, totalBytesRcvd, tmp.length - totalBytesRcvd)) == -1) {
				throw new SocketException("Connection closed prematurely");
			}
			totalBytesRcvd += bytesRcvd;
			byte[] copyOf = Arrays.copyOf(tmp, totalBytesRcvd);
			 
			try {
				parseData(copyOf,redis, equipCode);
			} catch (Exception e) {
				// TODO: handle exception
				LOG.error("能见度检测器："+equipCode+"数据解析错误");
			}
			 
		} catch (IOException se) {
			 
		}
	}

	/**
	 * 数据解析 @Title: parseData @Description: TODO( ) @param @param
	 * result @param @return @return String @throws
	 */
	public static void parseData(byte[] result,Jedis redis, String equipCode ) {
		String recData = "";
		String keyRealtime, totalName, value;
		for (int i = 0; i < result.length; i++) {
			recData = recData + result[i] + ",";
		}
		 
		if (result[0] == 1 && result[result.length - 1] == 4 && result[7] == 2 && result[10] == 0) {
			List<String> list = new ArrayList<>();
			String tmpString = "";
			Integer length = hex2Low(result[6]) - 6;
			for (int i = 14; i < length + 14; i++) {
				int tmp = result[i];
				if (tmp == 0) {
					tmpString = "00";
				}
				if (tmp < 0) {
					int hex2Low = hex2Low(result[i]);

					tmpString = Integer.toHexString(hex2Low);
				}
				if (tmp > 15) {
					int hex2Low = hex2Low(result[i]);
					tmpString = Integer.toHexString(hex2Low);
				}
				if (tmp <= 15 && tmp > 0) {
					int hex2Low = hex2Low(result[i]);
					tmpString = "0" + Integer.toHexString(hex2Low);
				}
				list.add(tmpString);
			}
			Collections.reverse(list);
			String dataResult = "";
			for (int j = 0; j < list.size(); j++) {

				dataResult = dataResult + list.get(j);
			}
			float intBitsToFloat = Float.intBitsToFloat(Integer.parseInt(dataResult, 16));
			LOG.info("能见度检测器："+equipCode+"能见度为："+intBitsToFloat);
			keyRealtime = CAL_NAME +  equipCode+ CAL_VALUE;
			totalName = TOTAL_CAR + CAL_VALUE;
			value = intBitsToFloat + SPLITTER_LEVEL0 + System.currentTimeMillis();
			redis.lpush(keyRealtime, value);// 单个车检仪器只保存最新的3000条数据
			redis.ltrim(keyRealtime, 0L, RECENT_LIST_COUNT);
			redis.set(totalName, value);// 总数只保留最新的一条
			jedisPool.returnResource(redis);
		}
	}

	/**
	 * 高低位转换
	 * 
	 * @param num
	 * @return
	 */
	public static int hex2Low(int num) {

		byte a = (byte) num;
		int i = a;
		i = a & 0xff;
		return i;
	}

	/**
	 * 判断是否断开连接，断开返回true,没有返回false
	 * 
	 * @param socket
	 * @return
	 */
	public Boolean isServerClose(Socket socket) {
		try {
			socket.sendUrgentData(0xFF);// 发送1个字节的紧急数据，默认情况下，服务器端没有开启紧急数据处理，不影响正常通信
			return false;
		} catch (Exception se) {
			return true;
		}
	}

	// ------------------------------------------------------------------------------
	public String getIp() {
		return ip;
	}

	public void setIp(String ip) {
		this.ip = ip;
	}

	public Integer getPort() {
		return port;
	}

	public void setPort(Integer port) {
		this.port = port;
	}
}
